package com.init.service.impl;


import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.init.common.ErrorCode;
import com.init.exception.BusinessException;
import com.init.mapper.AdminMapper;
import com.init.mapper.GradersMapper;
import com.init.model.dto.LoginUser;
import com.init.model.entity.Admin;
import com.init.model.entity.Graders;
import com.init.model.vo.LoginUserVO;
import com.init.service.AdminService;
import com.init.service.GradersService;
import com.init.service.LoginService;
import com.init.utils.JwtUtil;
import com.init.utils.RedisCache;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;



/**
 * @author Atanycosts
 * @date 2024/4/9
 */
@Slf4j
@Service
public class LoginServiceImpl implements LoginService {

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private AdminService adminService;



    @Resource
    private GradersService gradersService;


    @Resource
    private GradersMapper gradersMapper;


    /**
     * 注册的时候用 ,加密
     */
    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private RedisCache redisCache;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private LFUCacheService lfuCacheService;


    /**
     * 效验
     *
     * @param userAccount
     * @param userPassword
     */
    private static void checkAccountPwd(String userAccount, String userPassword) {
        // 1. 校验
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号错误");
        }
        if (userPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");
        }
    }

    /**
     * 管理员登录
     */
    @Override
    public LoginUserVO login(Admin admin) {

        if (Objects.isNull(admin)) {
            throw  new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        String userAccount = admin.getAdminAccount();
        String userPassword = admin.getAdminPassword();
        // 1. 校验
        checkAccountPwd(userAccount, userPassword);

        // 先封装
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                userAccount, userPassword);
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        // 如果为空
        if (Objects.isNull(authenticate)) {
            return null;
        }

        // 使用userid生成token
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        Admin userUser = loginUser.getAdmin();
        // 账户存进去
        String userId = userUser.getAdminAccount().toString();
        String jwt = JwtUtil.createJWT(userId);

        loginUser.setToken(jwt);

        // authenticate存入redis
        redisCache.setCacheObject(userId, loginUser);

        // 脱敏
        LoginUserVO loginAdminVo = getLoginAdminVo(userUser);

        // 把token响应给前端并设置user权限
        loginAdminVo.setToken(jwt);

        loginAdminVo.setStudentId(userUser.getAdminId());
        return loginAdminVo;
    }

    /**
     * 管理员脱敏
     */

    private static LoginUserVO getLoginAdminVo(Admin admin) {
        LoginUserVO vo = new LoginUserVO();
        vo.setStudentId(admin.getAdminId());
        vo.setStudentAccount(admin.getAdminAccount());
        vo.setStudentRole(admin.getAdminRole());
        return vo;
    }

    /**
     * 用户登录
     */
    @Override
    public LoginUserVO login(Graders graders) {

        // 已排查

        String jsonStr = stringRedisTemplate.opsForValue().get(graders.getUserAccount());
        if (StringUtils.isNotBlank(jsonStr)) {
            // 解析JSON字符串
            JSONObject jsonObject = JSONUtil.parseObj(jsonStr);

            // 提取User对象的JSON字符串
            String userJsonStr = jsonObject.getStr("graders");

            // 提取LoginUser对象的JSON字符串
            JSONObject userObject = JSONUtil.parseObj(userJsonStr);
            Graders bean = JSONUtil.toBean(userJsonStr, Graders.class);
            // 提取token
            String token = jsonObject.getStr("token");
            //2.存在，直接返回给用户
            LoginUserVO loginAdminVo = getLoginGradersVO(bean);
            loginAdminVo.setToken(token);
            log.info("缓存用户数据 : ");


            return loginAdminVo;
        }


        String userAccount = graders.getUserAccount();
        String userPassword = graders.getUserPassword();
        // 校验
        checkAccountPwd(userAccount, userPassword);

        // 先封装
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(
                        graders.getUserAccount(), graders.getUserPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);

        // 如果为空
        if (Objects.isNull(authenticate)) {
            return null;
        }
        // 使用userid生成token
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        Graders loginUserStudents = loginUser.getGraders();
        // getPatientAccount  唯一的
        String studentId = loginUserStudents.getUserAccount().toString();
        String jwt = JwtUtil.createJWT(studentId);
        loginUser.setToken(jwt);

        redisCache.setCacheObject(studentId, loginUser);
        // 脱敏
        LoginUserVO vo = getLoginGradersVO(loginUserStudents);

        // 把token响应给前端并设置user权限
        vo.setToken(jwt);
        // authenticate存入redis
        vo.setStudentId(loginUserStudents.getGraderId());

        // 更新访问次数
        lfuCacheService.updateAccessFrequency(graders.getUserAccount());
        return vo;
    }


    /**
     * 评定人脱敏
     * @return
     */

    private static LoginUserVO getLoginGradersVO(Graders graders) {
        LoginUserVO vo = new LoginUserVO();
        vo.setStudentId(graders.getGraderId());
        vo.setStudentAccount(graders.getUserAccount());
        vo.setStudentName(graders.getUserName());
        vo.setStudentGender(graders.getUserGender());
        vo.setStudentRole(graders.getUserRole());
        return vo;
    }


    /**
     * 管理员注册
     * @return
     */
    @Override
    public Boolean register(Admin admin) {

        String userAccount = admin.getAdminAccount();
        String userPassword = admin.getAdminPassword();

        // 1. 校验
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过短");
        }
        if (userPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码过短");
        }
        // 锁住,防止多次注册
        synchronized (userAccount.intern()) {
            // 查数据
            LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();
            //判断是否在数据库中存在
            Admin one = adminService.getOne(queryWrapper
                    .eq(Admin::getAdminAccount, userAccount));

            // 存在账户
            if (one != null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
            }

            //HmacSHA256进行加密
            String encode = passwordEncoder.encode(userPassword);
            boolean matches = passwordEncoder.matches(userPassword, encode);
            System.out.println("/n");
            System.out.println(matches);
            log.info("密码匹配：", matches);
            admin.setAdminPassword(encode);

            //设置角色
            if (StringUtils.isAnyBlank(admin.getAdminRole())) {
                admin.setAdminRole("ROLE_ADMIN");
            }

            //保存
            boolean save = adminService.save(admin);

            if (!save) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "注册失败，数据库错误");
            }

            return true;
        }

    }

    /**
     * 学生注册
     * @return
     */
    @Override
    public Boolean register(Graders graders) {

        String userAccount = graders.getUserAccount();
        String userPassword = graders.getUserPassword();

        // 1. 校验
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过短");
        }
        if (userPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码过短");
        }
        // 锁住,防止多次注册
        synchronized (userAccount.intern()) {
            // 查数据
            LambdaQueryWrapper<Graders> queryWrapper = new LambdaQueryWrapper<>();
            // 判断是否在数据库中存在
            Graders one = gradersService.getOne(queryWrapper
                    .eq(Graders::getUserAccount, userAccount));

            // 存在账户
            if (one != null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
            }

            // HmacSHA256进行密码的加密
            String encode = passwordEncoder.encode(userPassword);
            graders.setUserPassword(encode);

            // 设置角色
            if (StringUtils.isAnyBlank(graders.getUserRole())) {
                graders.setUserRole("ROLE_USER");
            }

            // 保存
            int insert = gradersMapper.insert(graders);

            if (insert != 0) {
                return true;
            }

            return false;
        }

    }


    /**
     * 退出登录
     */
    @Override
    public void logout() {

        // 已排查

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null) {
            // 清理SecurityContext
            SecurityContextHolder.clearContext();
            SecurityContextHolder.getContext().setAuthentication(null);

            // 获取当前用户的会话ID或用户ID
            String sessionId = authentication.getName();
            // 删除Redis中的会话信息
            stringRedisTemplate.delete(sessionId);
        }

        log.info("退出登录");

    }
}
